#!/usr/bin/python
# -*- coding: utf-8 -*-
import unittest


########################################################################
## code source from:
#            http://wiki.python.org/moin/PythonDecoratorLibrary
#
########################################################################

# method synchronization
# Example usage:
#from threading import Lock
#my_lock = Lock()
#@synchronized(my_lock)
#def critical1(*args):
#    # Interesting stuff goes here.
#    pass
#
#@synchronized(my_lock)
#def critical2(*args):
#    # Other interesting stuff goes here.
#    pass

def synchronized(lock_instance):
    def wrap(a_function):
        def new_function(*args, **kw):
            lock_instance.acquire()
            try:
                return a_function(*args, **kw)
            finally:
                lock_instance.release()
        return new_function
    return wrap


# singleton declaration
# Example usage:
#@singleton
#class MySingletonClass(object):
#    def __init__(self):
#        pass
#    def my_method(self):
#        pass
#
# MySingletonClass is now a singleton !
# -------------------------------------
    

def singleton(cls):
    instances = {}
    def get_instance():
        if cls not in instances:
            instances[cls] = cls()
        return instances[cls]
    return get_instance

####################### Singleton unit test ############################
@singleton
class TestSingletonClass(object):
    def __init__(self):
        self.__string = ''    
    def set_string(self, a_string):
        self.__string = a_string        
    def get_string(self):
        return self.__string

class TestSingleton(unittest.TestCase):
    def test_creation(self):
        """TestSingleton: creation test"""
        oo1 = TestSingletonClass()
        oo2 = TestSingletonClass()
        oo3 = TestSingletonClass()        
        self.assertEqual(oo1, oo2)
        self.assertEqual(oo1, oo3)
        self.assertEqual(oo3, oo2)
    
    def test_set_and_get(self):
        """TestSingleton: creation test"""
        oo1 = TestSingletonClass()
        oo2 = TestSingletonClass()
        oo3 = TestSingletonClass()
        oo1.set_string("oo1")
        oo2.set_string("oo2")
        oo3.set_string("oo3")
        self.assertEqual(oo1.get_string(), oo2.get_string())
        self.assertEqual(oo1.get_string(), oo3.get_string())
        self.assertEqual(oo3.get_string(), oo2.get_string())
        
if __name__ == "__main__":
    unittest.main()